/*
 * @Author: xiaosihan 
 * @Date: 2024-05-27 23:00:12 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-05-29 16:15:47
 */

import { AdditiveBlending, BoxGeometry, DoubleSide, Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, PlaneGeometry, RepeatWrapping, SRGBColorSpace } from "three";
import Transition from "three-base/Transition";
import threeLoader from "three-base/threeLoader";
import huiguangPNG from "./huiguang.png";

export type BarData = {
    name: string,
    enName: string,
    value: number,
    index: number,
    height: number,
    color: string,
    center: Array<number>,
    centroid: Array<number>,
}

// 3d柱子
export default class Bar extends Group {
    constructor(barData: BarData) {
        super();
        Object.assign(this.barData, barData);
        this.rotation.x = -Math.PI / 2;
        this.barMesh.geometry = new BoxGeometry(0.1 * 0.7, 0.1 * 0.7, barData.height);
        this.barMesh.geometry.translate(0, 0, barData.height / 2);
        this.createHUIGUANG(barData.height, barData.color);
        this.transtion.setDelay(barData.index * 100).set({
            value: barData.value,
            height: barData.height
        })
    }

    material = new MeshBasicMaterial({
        color: 0xffffff,
        transparent: true,
        opacity: 1,
        depthTest: false,
        fog: false,
    })

    renderOrder = 5;

    //中间的柱子
    barMesh = (() => {
        const barMesh = new Mesh(undefined, this.material);
        this.add(barMesh);
        return barMesh;
    })();

    //柱状图的标签
    lable = (() => {
        const lable = new Object3D();
        lable.rotateX(Math.PI / 2);
        lable.scale.set(0.01, 0.01, 0.01);
        lable.visible = false;
        this.add(lable);
        return lable;
    })();

    //柱状图数据
    barData: BarData = {
        name: "",
        enName: "",
        value: 0,
        index: 0,
        height: 0,
        color: "#ffffff",
        center: [0, 0],
        centroid: [0, 0],
    }

    // 动画控制对象
    transtion = (() => {
        const transtion = new Transition({ value: 0, height: 0 });
        transtion.setBezier([0.25, 0.83, 0.24, 0.84]);
        transtion.setDuration(1500);
        transtion.onChange(({ value, height }) => {
            this.barMesh.scale.set(1, 1, (value / this.barData.value) || 0);
            this.lable.visible = (height > 0.1);
            this.lable.position.set(1, 0, height + 0.5);
            const lableDom = document.getElementById(this.barData.name);
            if (lableDom) {
                const valueDom = lableDom.getElementsByClassName("value");
                if (valueDom[0]) {
                    valueDom[0].innerHTML = String(Math.ceil(value));
                }
            }
        });
        return transtion;
    })();

    // 创建辉光模型
    createHUIGUANG(h: number, color: string) {
        let geometry = new PlaneGeometry(0.35, h)
        geometry.translate(0, h / 2, 0)
        const texture = threeLoader.getTexture(huiguangPNG);
        texture.colorSpace = SRGBColorSpace
        texture.wrapS = RepeatWrapping
        texture.wrapT = RepeatWrapping
        let material = new MeshBasicMaterial({
            color: color,
            map: texture,
            transparent: true,
            opacity: 0.4,
            depthWrite: false,
            side: DoubleSide,
            blending: AdditiveBlending,
        })
        let mesh = new Mesh(geometry, material)
        mesh.name = "辉光"
        mesh.renderOrder = 10
        mesh.rotateX(Math.PI / 2)
        let mesh2 = mesh.clone()
        let mesh3 = mesh.clone()
        mesh2.rotateY((Math.PI / 180) * 60)
        mesh3.rotateY((Math.PI / 180) * 120)
        this.barMesh.add(mesh, mesh2, mesh3);
    }

    epsilon(value: number) {
        return Math.abs(value) < 1e-10 ? 0 : value;
    }

    getObjectCSSMatrix(matrix: Matrix4) {
        const elements = matrix.elements;
        const matrix3d = "matrix3d(" + this.epsilon(elements[0]) + "," + this.epsilon(elements[1]) + "," + this.epsilon(elements[2]) + "," + this.epsilon(elements[3]) + "," + this.epsilon(-elements[4]) + "," + this.epsilon(-elements[5]) + "," + this.epsilon(-elements[6]) + "," + this.epsilon(-elements[7]) + "," + this.epsilon(elements[8]) + "," + this.epsilon(elements[9]) + "," + this.epsilon(elements[10]) + "," + this.epsilon(elements[11]) + "," + this.epsilon(elements[12]) + "," + this.epsilon(elements[13]) + "," + this.epsilon(elements[14]) + "," + this.epsilon(elements[15]) + ")";
        return "translate(-50%,-50%)" + matrix3d;
    }

    updateMatrix(): void {
        const m = this.lable.matrixWorld;
        const lableDom = document.getElementById(this.barData.name);
        if (lableDom) {
            Object.assign(lableDom.style, {
                transform: this.getObjectCSSMatrix(m),
                opacity: this.lable.visible ? 1 : 0
            })
        }

        super.updateMatrix();
    }
}